#ifndef NETSERVICE_H
#define NETSERVICE_H

#include "core_global.h"
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <boost/asio/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>

class TcpConnection;
class TcpAcceptor;
class AsyncService;

class NetService : protected boost::noncopyable
{
public:
    typedef boost::function< void (unsigned long, int) > AcceptHandler;
    typedef boost::function< size_t (size_t) > FilterHandler;
    typedef boost::function< void (size_t, int) > CompleteHandler;

    typedef boost::shared_ptr< TcpConnection > ConnectionPtr;
    typedef boost::shared_ptr< TcpAcceptor > AcceptorPtr;

    typedef boost::unordered_set< ConnectionPtr > ConnectionSet;
    typedef boost::unordered_map< unsigned long, ConnectionPtr > ConnectionMap;

    typedef boost::mutex Mutex;
    typedef Mutex::scoped_lock ScopedLock;
    typedef boost::system::error_code ErrorCode;

public:
    NetService(AsyncService &service);
    ~NetService();

    int  init();
    int  open(const std::string &host, unsigned short port, int listenCount);
    int  close();
    int  close(unsigned long key);
    int  remote(std::string &host, unsigned short &port);

    void accept(BOOST_ASIO_MOVE_ARG(AcceptHandler) handler);

    void read(unsigned long key, void *buf, size_t size,
              BOOST_ASIO_MOVE_ARG(FilterHandler) filter,
              BOOST_ASIO_MOVE_ARG(CompleteHandler) handler);

    void write(unsigned long key, const void *buf, size_t size,
               BOOST_ASIO_MOVE_ARG(FilterHandler) filter,
               BOOST_ASIO_MOVE_ARG(CompleteHandler) handler);

protected:
    size_t isComplete(FilterHandler filter, size_t size);

    void onComplete(ConnectionPtr con, CompleteHandler handler, size_t size, int err);
    void onAccepted(ConnectionPtr con, AcceptHandler handler, int err);

private:
    AsyncService &m_service;

    AcceptorPtr m_acceptor;

    ConnectionSet m_trash;

    ConnectionMap m_map;

    Mutex m_trashLock;

    Mutex m_mapLock;
};

#endif // NETSERVICE_H
